package com.content.service.xxljob;

import com.content.base.exception.XueChengPlusException;
import com.content.model.dto.CourseIndex;
import com.content.model.po.CoursePublish;
import com.content.service.config.MultipartSupportConfig;
import com.content.service.feignclient.MediaServiceClient;
import com.content.service.feignclient.SearchServiceClient;
import org.apache.commons.io.IOUtils;
import com.content.model.dto.CoursePreviewDto;
import com.content.model.po.MqMessage;
import com.content.service.CoursePublishService;
import com.content.service.MessageProcessAbstract;
import com.content.service.MqMessageService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class CoursePublishSchedule extends MessageProcessAbstract {

    @Autowired
    MediaServiceClient mediaServiceClient;

    @Autowired
    SearchServiceClient searchServiceClient;

    @Autowired
    CoursePublishService coursePublishService;
    //任务调度入口
    @XxlJob("CoursePublishJobHandler")
    public void coursePublishJobHandler() {
        // 分片参数
        int shardIndex = XxlJobHelper.getShardIndex();
        int shardTotal = XxlJobHelper.getShardTotal();
        log.debug("shardIndex="+shardIndex+",shardTotal="+shardTotal);
        //参数:分片序号、分片总数、消息类型、一次最多取到的任务数量、一次任务调度执行的超时时间
        process(shardIndex,shardTotal,"course_publish",30,60);
    }

    //课程发布任务处理
    @Override
    public boolean execute(MqMessage mqMessage) {
        //获取消息相关的业务信息
        String businessKey1 = mqMessage.getBusinessKey1();
        long courseId = Integer.parseInt(businessKey1);

        MqMessageService mqMessageService = this.getMqMessageService();
        int stageOne = mqMessageService.getStageOne(mqMessage.getId());
        int stageTwo = mqMessageService.getStageTwo(mqMessage.getId());
        int stageThree = mqMessageService.getStageThree(mqMessage.getId());

        //课程静态化
        generateCourseHtml(mqMessage,courseId);
        //课程索引
        saveCourseIndex(mqMessage,courseId);
        //课程缓存
        saveCourseCache(mqMessage,courseId);

        if(!(stageOne > 0 && stageTwo > 0 && stageThree > 0)){
            return false;
        }

        return true;
    }


    //生成课程静态化页面并上传至文件系统
    public void generateCourseHtml(MqMessage mqMessage,long courseId){

        log.debug("开始进行课程静态化,课程id:{}",courseId);
        //消息id
        Long id = mqMessage.getId();
        //消息处理的service
        MqMessageService mqMessageService = this.getMqMessageService();
        //消息幂等性处理
        int stageOne = mqMessageService.getStageOne(id);
        if(stageOne >0){
            log.debug("课程静态化已处理直接返回，课程id:{}",courseId);
            return ;
        }

        String status = null;

        try {
            //配置freemarker
            Configuration configuration = new Configuration(Configuration.VERSION_2_3_30);

            //加载模板
            //选指定模板路径，classpath下templates下
            //得到classpath路径
            String classpath = Objects.requireNonNull(this.getClass().getResource("/")).getPath();
            configuration.setDirectoryForTemplateLoading(new File(classpath+"/templates/"));

            //设置字符编码
            configuration.setDefaultEncoding("utf-8");

            //指定模板文件名称
            Template template = configuration.getTemplate("course_template.ftl");

            //准备数据
            CoursePreviewDto coursePreviewInfo = coursePublishService.getCoursePreviewInfo(courseId);

            HashMap<String, Object> map = new HashMap<>();
            map.put("model",coursePreviewInfo);

            //静态化
            //参数1：模板，参数2：数据模型
            String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
            System.out.println(content);

            InputStream inputStream = IOUtils.toInputStream(content);

            //创建临时文件
            File file = File.createTempFile(String.valueOf(courseId), ".html");

            String fileAbsolutePath = file.getAbsolutePath();
            log.debug("文件生成路径:{}",file.getAbsolutePath());

            //输出流
            FileOutputStream outputStream = new FileOutputStream(fileAbsolutePath);

            //将静态化内容写到文件中
            IOUtils.copy(inputStream,outputStream);
            MultipartFile multipartFile = MultipartSupportConfig.getMultipartFile(new File(fileAbsolutePath));
            status = mediaServiceClient.uploadFile(multipartFile, "course/" + courseId + ".html");
        } catch (IOException | TemplateException e) {
            throw new RuntimeException(e);
        }

        if(status != null){
            //保存第一阶段状态
            mqMessageService.completedStageOne(id);
        }
    }

    //将课程信息缓存至redis
    public void saveCourseCache(MqMessage mqMessage,long courseId){
        log.debug("将课程信息缓存至redis,课程id:{}",courseId);
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }


    }
    //保存课程索引信息
    public void saveCourseIndex(MqMessage mqMessage,long courseId){
        log.debug("保存课程索引信息,课程id:{}",courseId);
        try {
            //查询课程发布信息
            CoursePublish coursePublish = coursePublishService.getById(courseId);
            if(coursePublish == null){
                log.debug("课程信息为空，无法生成索引");
                return ;
            }

            MqMessageService mqMessageService = this.getMqMessageService();

            //判断消息的第二阶段状态
            if(mqMessageService.getStageTwo(mqMessage.getId()) > 0){
                log.debug("课程索引已生成，无需生成");
                return ;
            }

            CourseIndex courseIndex = new CourseIndex();
            BeanUtils.copyProperties(coursePublish,courseIndex);

            //否则则生成索引
            Boolean add = searchServiceClient.add(courseIndex);
            if (!add){
                log.error("远程调用搜索服务添加索引失败:{}",courseId);
            }else {
                //保存第二阶段状态
                mqMessageService.completedStageTwo(mqMessage.getId());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }


}
